using System;
using System.Drawing;
using System.Windows.Forms;
using GTA;
using GTA.Native;
using GTA.Math;


namespace LaserEye
{
    public class LaserEye : Script
    {
        Player player = Game.Player;
        Ped playerPed = Game.Player.Character;
        Color lasercol;
        bool toggle = false;
        bool HasExplosion = true;
        bool LaserEyeOn = false;
        int expInterval = 10;
        int startexp;

        public LaserEye()
        {
            lasercol = Color.FromArgb(255, 255, 0, 0);
            Tick += OnTick;
            KeyDown += OnKeyDown;
            KeyUp += OnKeyUp;

            Interval = 0;
        }

        unsafe void OnTick(object sender, EventArgs e)
        {
            player = Game.Player;
            playerPed = Game.Player.Character;
            bool UsingGamepad = Function.Call<bool>(Hash._GET_LAST_INPUT_METHOD);

            if (player.IsDead)
            {
                if (LaserEyeOn)
                {
                    LaserEyeOn = false;
                }
            }

            if (LaserEyeOn)
            {
                RaycastResult RayCast = this.Cam_Raycast_Forward();

                if (RayCast.DitHitAnything)
                {
                    Vector3 hitcoord = RayCast.HitCoords;
                    Vector3 LeftEyeCoords = playerPed.GetBoneCoord(Bone.FACIAL_facialRoot, new Vector3(-0.037f, 0, 0));
                    Vector3 RightEyeCoords = playerPed.GetBoneCoord(Bone.FACIAL_facialRoot, new Vector3(0.037f, 0, 0));
                    Vector3 dotsize = new Vector3(0.016f, 0.016f, 0.016f);

                    if (hitcoord != new Vector3(0, 0, 0))
                    {
                        Vector3 offset = RightEyeCoords - playerPed.GetBoneCoord(Bone.FACIAL_facialRoot);
                        Vector3 hitcoordL = RayCast.HitCoords - offset;
                        Vector3 hitcoordR = RayCast.HitCoords + offset;
                        if (World.GetDistance(playerPed.Position, hitcoord) < 7)
                            dotsize = new Vector3(0.009f, 0.009f, 0.009f);
                        playerPed.Task.LookAt(hitcoord);
                        Function.Call(Hash.DRAW_LINE, LeftEyeCoords.X, LeftEyeCoords.Y, LeftEyeCoords.Z, hitcoordL.X, hitcoordL.Y, hitcoordL.Z, lasercol.R, lasercol.G, lasercol.B, 255);
                        Function.Call(Hash.DRAW_LINE, RightEyeCoords.X, RightEyeCoords.Y, RightEyeCoords.Z, hitcoordR.X, hitcoordR.Y, hitcoordR.Z, lasercol.R, lasercol.G, lasercol.B, 255);
                        //World.DrawMarker(MarkerType.DebugSphere, hitcoord, new Vector3(0, 0, 0), new Vector3(0, 0, 0), dotsize, lasercol);
                        if (Game.GameTime >= startexp + expInterval)
                        {
                            if (HasExplosion)
                                World.AddExplosion(hitcoord, ExplosionType.Grenade, 2.0f, 0.1f);
                            Function.Call(Hash.START_SCRIPT_FIRE, hitcoord.X, hitcoord.Y, hitcoord.Z, 5000, false);
                            if (RayCast.DitHitEntity && RayCast.HitEntity.Handle != playerPed.Handle)
                            {
                                Entity ent = RayCast.HitEntity;
                                if (Function.Call<bool>(Hash.IS_ENTITY_A_PED, ent))
                                    Function.Call(Hash.SET_PED_TO_RAGDOLL, ent, 3000, 3000, 0, 1, 1, 1);
                                if (Function.Call<bool>(Hash.IS_ENTITY_A_VEHICLE, ent))
                                {
                                    if (!ent.IsDead)
                                        HitVehicle(ent);
                                    ent.ApplyForce((ent.Position - LeftEyeCoords) * 0.2f / (ent.Position - LeftEyeCoords).Length());
                                }
                                else
                                {
                                    Function.Call(Hash.APPLY_PED_DAMAGE_PACK, ent.Handle, "BigHitByVehicle", 50f, 1f);
                                    ent.ApplyForce((ent.Position - LeftEyeCoords) * 3.5f / (ent.Position - LeftEyeCoords).Length());
                                }
                                Function.Call(Hash.START_ENTITY_FIRE, ent);
                            }
                            startexp = Game.GameTime;
                        }
                    }
                }
            }
            if (UsingGamepad == false)
            {
                if (Game.IsControlPressed(2, GTA.Control.ScriptPadLeft) && Game.IsControlPressed(2, GTA.Control.FrontendAccept))
                {
                    if (toggle)
                    {
                        toggle = false;
                        UI.ShowSubtitle("HeatVision OFF");
                        Wait(200);
                    }
                    else if (!toggle)
                    {
                        toggle = true;
                        UI.ShowSubtitle("HeatVision ON");
                        Wait(200);
                    }
                }
                if (Game.IsControlPressed(2, GTA.Control.ScriptLT) && toggle)
                {
                    LaserEyeOn = true;
                }
                else
                {
                    LaserEyeOn = false;
                }
            }
        }

        void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Q)
            {
                LaserEyeOn = !LaserEyeOn;
                startexp = Game.GameTime;
            }
        }

        void OnKeyUp(object sender, KeyEventArgs e)
        {

        }

        void HitVehicle(Entity ent)
        {
            if (Function.Call<bool>(Hash.IS_VEHICLE_SEAT_FREE, ent, -1) && Function.Call<bool>(Hash.IS_VEHICLE_ALARM_ACTIVATED, ent))
                Function.Call(Hash.SET_VEHICLE_ALARM, ent, true);

            for (int i = 0; i < 8; i++)
            {
                // Function.Call(Hash.SET_VEHICLE_TYRE_BURST, ent, i, true, 1000.0f);
            }

            for (int i = 0; i < 4; i++)
            {
                Function.Call(Hash.SMASH_VEHICLE_WINDOW, ent, i);
            }

            if (Function.Call<bool>(Hash.IS_VEHICLE_ATTACHED_TO_TRAILER, ent))
                Function.Call(Hash.DETACH_VEHICLE_FROM_TRAILER, ent);
            Function.Call(Hash._DETACH_VEHICLE_WINDSCREEN, ent.Handle);

            Vector3 realdir = (playerPed.Position - ent.Position);
            realdir.Normalize();
            Vector3 dir = realdir * 3 / realdir.Length();
            Function.Call(Hash.SET_VEHICLE_DAMAGE, ent, dir.X, dir.Y, dir.Z, 50.5f, 2.0f, true);

            float health = Function.Call<float>(Hash.GET_VEHICLE_ENGINE_HEALTH, ent);
            if (health < -2000f)
                Function.Call(Hash.EXPLODE_VEHICLE, ent, true, true);
            else
                Function.Call(Hash.SET_VEHICLE_ENGINE_HEALTH, ent, health - 15f);
        }

        protected override void Dispose(bool A_0)
        {
            if (A_0)
            {

            }
        }

        public Vector3 RotToDir(Vector3 Rot)
        {
            try
            {
                float z = Rot.Z;
                float retz = z * 0.0174532924F;
                float x = Rot.X;
                float retx = x * 0.0174532924F;
                float absx = (float)System.Math.Abs(System.Math.Cos(retx));
                return new Vector3((float)-System.Math.Sin(retz) * absx, (float)System.Math.Cos(retz) * absx, (float)System.Math.Sin(retx));
            }
            catch
            {
                return new Vector3(0, 0, 0);
            }

        }

        public RaycastResult Cam_Raycast_Forward()
        {
            try
            {
                Vector3 multiplied = new Vector3(RotToDir(NC_Get_Cam_Rotation()).X * 5000.0f, RotToDir(NC_Get_Cam_Rotation()).Y * 5000.0f, RotToDir(NC_Get_Cam_Rotation()).Z * 5000.0f);
                RaycastResult ray = World.Raycast(NC_Get_Cam_Position(), NC_Get_Cam_Position() + multiplied, IntersectOptions.Everything);
                return ray;
            }
            catch
            {
                return new RaycastResult();
            }
        }

        public Vector3 NC_Get_Cam_Position()
        {
            try
            {
                return Function.Call<Vector3>(Hash.GET_GAMEPLAY_CAM_COORD);
            }
            catch
            {

            }
            return new Vector3(0, 0, 0);
        }

        public Vector3 NC_Get_Cam_Rotation()
        {
            try
            {
                return Function.Call<Vector3>(Hash.GET_GAMEPLAY_CAM_ROT, 0);
            }
            catch
            {

            }
            return new Vector3(0, 0, 0);
        }
    }
}